package com.gcb.service.impl;

import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gcb.common.constant.CacheConstants;
import com.gcb.common.core.domain.entity.GcbUser;
import com.gcb.common.core.redis.RedisCache;
import com.gcb.common.enums.*;
import com.gcb.common.exception.ServiceException;
import com.gcb.common.utils.*;
import com.gcb.common.utils.bean.BeanUtils;
import com.gcb.domain.dto.*;
import com.gcb.domain.vo.*;
import com.gcb.domain.vo.company.ComInfoVO;
import com.gcb.mapper.GcbUserMapper;
import com.gcb.service.ICompanyService;
import com.gcb.service.ICrewService;
import com.gcb.service.IGcbUserService;
import com.gcb.utils.GcbUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 工船宝用户信息Service业务层处理
 *
 * @author seh
 * @date 2024-03-08
 */
@Service
public class GcbUserServiceImpl extends ServiceImpl<GcbUserMapper, GcbUser> implements IGcbUserService {

    @Autowired
    private GcbUserMapper gcbUserMapper;

    @Autowired
    private ICompanyService companyService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ICrewService crewService;

    @Autowired
    private TokenUtil tokenUtil;

    @Autowired
    private GcbUtils gcbUtils;

    /**
     * 查询工船宝用户信息
     *
     * @param id 工船宝用户信息主键
     * @return 工船宝用户信息
     */
    @Override
    public GcbUser selectGcbUserById(Long id) {
        return this.getById(id);
    }

    /**
     * 查询工船宝用户信息列表
     *
     * @return 工船宝用户信息
     */
    @Override
    public List<GcbUserVO> selectGcbUserList(GcbUserQueryDTO dto) {
        List<GcbUserVO> pageVo = gcbUserMapper.selectGcbUserList(dto);
        for (GcbUserVO vo : pageVo) {
            vo.setStatusStr(CommonStatusEnum.getInfo(vo.getStatus()));
            vo.setSexStr(SexTypeEnum.getInfo(vo.getSex()));
            vo.setSignTypeStr(CreateTypeEnum.getInfo(vo.getSignType()));
            vo.setCrewAuthStatusStr(AuthStatusEnum.getInfo(vo.getCrewAuthStatus()));
            vo.setAuthStatusStr(AuthStatusEnum.getInfo(vo.getAuthStatus()));
            vo.setSignTypeStr(CreateTypeEnum.getInfo(vo.getSignType()));
            if (StringUtils.isNotEmpty(vo.getIdentityCard())) {
                vo.setIdentityCard(DesensitizedUtil.idCardNum(vo.getIdentityCard(), 3, 4));
            }
            //手机号脱敏
            if (StringUtils.isNotEmpty(vo.getMobile())) {
                vo.setMobile(DesensitizedUtil.mobilePhone(vo.getMobile()));
            }
        }
        return pageVo;
    }

    /**
     * 修改工船宝用户信息
     *
     * @param gcbUser 工船宝用户信息
     * @return 结果
     */
    @Override
    public int updateGcbUser(GcbUser gcbUser) {
        gcbUser.setUpdateTime(DateUtils.getNowDate());
        boolean update = this.updateById(gcbUser);
        if (update) return 1;
        return 0;
    }

    /**
     * 根据手机号码查询用户信息
     *
     * @param mobile 手机号码
     * @return
     */
    @Override
    public GcbUser getByMobile(String mobile) {
        return gcbUserMapper.getByMobile(mobile);
    }

    /**
     * 修改用户密码
     *
     * @param dto
     * @return
     */
    @Override
    public int updatePassword(GcbUserUpdatePasswordDTO dto) {
        // 获取用户id
        Long id = dto.getId();
        // 根据用户id获取用户信息
        GcbUser user = gcbUserMapper.selectById(id);
        //如果未查询到用户信息
        if (Objects.nonNull(user)) {
            //用户输入的原密码
            String password = dto.getPassword();
            //用户输入的新密码
            String newPassword = dto.getNewPassword();
            //判断用户输入的原密码是否为数据库中的旧密码
            boolean matchesPassword = PasswordUtils.matchesPassword(password, user.getPassword());
            //如果匹配
            if (matchesPassword) {
                //加密新密码
                String passwordEncrypt = PasswordUtils.encryptPassword(newPassword);
                //重新设置密码
                GcbUser gcbUser = new GcbUser();
                gcbUser.setId(id);
                gcbUser.setPassword(passwordEncrypt);
                gcbUser.setUpdateTime(DateUtils.getNowDate());
                return gcbUserMapper.updateById(gcbUser);
            } else {
                throw new ServiceException("原密码错误！");
            }
        } else {
            throw new ServiceException("用户不存在！");
        }
    }

    /**
     * 注册用户设置新密码
     *
     * @param userPwdDTO 用户密码对象
     * @return boolean
     */
    @Override
    public Boolean registerPassword(GcbUserUpdatePasswordDTO userPwdDTO) {
        //用户输入的密码
        String password = userPwdDTO.getPassword();
        //用户输入的确认密码
        String newPassword = userPwdDTO.getNewPassword();
        //判断用户输入的密码是否与确认密码一致
        if (!StringUtils.equals(password, newPassword)) {
            throw new ServiceException("两次密码不一致");
        }
        // 获取用户id
        Long id = userPwdDTO.getId();
        // 根据用户id获取用户信息
        GcbUser user = gcbUserMapper.selectById(id);
        if (Objects.isNull(user)) {
            throw new ServiceException("您还未注册！");
        }
        //获取用户手机号
        String mobile = user.getMobile();
        //查看密码是否与手机号码后6位一致 如果不一致说明用户已经修改过初始密码
        boolean matchesPassword = PasswordUtils.matchesPassword(mobile.substring(mobile.length() - 6), user.getPassword());
        //如果不匹配 说明用户已经设置过新密码
        if (!matchesPassword) {
            throw new ServiceException("您已设置过初始密码！");
        }
        //开始更新密码
        //加密新密码
        String passwordEncrypt = PasswordUtils.encryptPassword(newPassword);
        //重新设置密码
        GcbUser gcbUser = new GcbUser();
        gcbUser.setId(id);
        gcbUser.setPassword(passwordEncrypt);
        gcbUser.setUpdateTime(DateUtils.getNowDate());
        return 1 == gcbUserMapper.updateById(gcbUser);
    }

    /**
     * 忘记密码
     *
     * @param dto
     * @return
     */
    @Override
    public int forgetPwd(GcbUserForgetPasswordDTO dto) {
        String mobile = dto.getMobile();
        String verifyKey = CacheConstants.APP_VERIFY_CODE_KEY + StringUtils.nvl(mobile, "");
        GcbUser byMobile = gcbUserMapper.getByMobile(mobile);
        if (Objects.nonNull(byMobile)) {
            String passwordEncrypt = PasswordUtils.encryptPassword(dto.getNewPassword());
            GcbUser gcbUser = new GcbUser();
            gcbUser.setId(byMobile.getId());
            gcbUser.setPassword(passwordEncrypt);
            gcbUser.setUpdateTime(DateUtils.getNowDate());
            int i = gcbUserMapper.updateById(gcbUser);
            //修改用户密码后 删除验证码
            redisCache.deleteObject(verifyKey);
            return i;
        } else {
            throw new ServiceException("用户不存在");
        }
    }

    @Override
    public void checkVerifyCode(String mobile, String verifyCode) {
        String verifyKey = CacheConstants.APP_VERIFY_CODE_KEY + StringUtils.nvl(mobile, "");
        String verifyCodeCache = redisCache.getCacheObject(verifyKey);
        if (StringUtils.isBlank(verifyCodeCache)) {
            throw new ServiceException("系统错误，请重新发送验证码");
        }

        if (!verifyCodeCache.equalsIgnoreCase(verifyCode)) {
            throw new ServiceException("验证码错误");
        }

        redisCache.deleteObject(verifyKey);
    }

    /**
     * 修改用户身份标签
     *
     * @param userId      用户id
     * @param identityTag 标签
     * @author ych
     */
    @Override
    public Boolean identity(Long userId, String identityTag) {
        return gcbUserMapper.identity(userId, identityTag) == 1;
    }

    /**
     * 用户注册验证验证码
     *
     * @param userRegisterDTO 用户注册对象
     * @author ych
     */
    @Override
    public String register(UserRegisterDTO userRegisterDTO) {
        String phone = userRegisterDTO.getPhone();
        String redisCode = redisCache.getCacheObject(CacheConstants.APP_VERIFY_CODE_KEY + phone);
        if (Objects.isNull(redisCode)) {
            throw new ServiceException("验证码不存在");
        }
        if (StringUtils.isBlank(redisCode) || !redisCode.equals(userRegisterDTO.getCode())) {
            throw new ServiceException("验证码错误");
        }
        // 判断用户是否已经使用手机号注册
        if (Objects.nonNull(gcbUserMapper.selectOne(new LambdaQueryWrapper<GcbUser>().eq(GcbUser::getMobile, phone)))) {
            throw new ServiceException("该手机号已注册");
        }
        // 初始化用户信息
        GcbUser gcbUser = gcbUtils.initUserInfo(phone, CreateTypeEnum.USER, 0L);
        int i = gcbUserMapper.insert(gcbUser);
        return tokenUtil.getToken(gcbUser.getId());
    }


    /**
     * 根据用户id获取用户信息
     *
     * @param userId 用户id
     * @return GcbUserInfoVo
     * @author ych
     */
    @Override
    public GcbUserInfoVO userInfo(Long userId) {
        if (Objects.isNull(userId)) {
            throw new ServiceException("用户id不能为空");
        }
        GcbUserInfoVO gcbUserInfoVo = new GcbUserInfoVO();
        GcbUser gcbUser = gcbUserMapper.selectById(userId);
        BeanUtils.copyProperties(gcbUser, gcbUserInfoVo);

        //计算工作时间
        String workTime = calculateWorkTime(gcbUser.getWorkDate());
        gcbUserInfoVo.setWorkDate(workTime);
        //转换手机号
        gcbUserInfoVo.setMobile(gcbUser.getMobile().substring(0, 3) + "****" + gcbUser.getMobile().substring(7));
        //转换创建时间
        gcbUserInfoVo.setCreateTime(new SimpleDateFormat("yyyy-MM-dd").format(gcbUser.getCreateTime()));
        //如果实名认证 处理身份证号码
        if (gcbUser.getAuthStatus().equals(1)) {
            gcbUserInfoVo.setIdentityCard(gcbUser.getIdentityCard().substring(0, 3) + "************" + gcbUser.getIdentityCard().substring(gcbUser.getIdentityCard().length() - 4));
        }
        //设置身份证是否实名认证
        gcbUserInfoVo.setIdAuthStatus(gcbUser.getAuthStatus());
        //转换tag
        if (StringUtils.isBlank(gcbUser.getTag())) {
            //空集合
            gcbUserInfoVo.setTag(new ArrayList<>());
        } else {
            gcbUserInfoVo.setTag(Arrays.stream(gcbUser.getTag().split("-")).collect(Collectors.toList()));
        }
        //查询船员认证
        CrewVO crew = crewService.getByUserId(userId);
        if (Objects.isNull(crew)) {
            gcbUserInfoVo.setCrewAuthState(1);
        } else {
            gcbUserInfoVo.setCrewAuthState(crew.getAuthStatus());
            //如果认证时间不为null才计算
            if (!Objects.isNull(crew.getAuthTime())) {
                gcbUserInfoVo.setCrewAuthTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(crew.getAuthTime()));
            }
        }
        return gcbUserInfoVo;
    }

    @Override
    public void updateStatus(GcbUserSaveDTO dto) {
        gcbUserMapper.updateBatchStatus(dto);
    }

    @Override
    public GcbUserVO getDetail(Long id) {
        GcbUserVO vo = gcbUserMapper.selectDetailById(id);
        if (Objects.isNull(vo)) {
            return new GcbUserVO();
        }
        vo.setSexStr(SexTypeEnum.getInfo(vo.getSex()));
        vo.setStatusStr(CommonStatusEnum.getInfo(vo.getStatus()));
        vo.setSignTypeStr(CreateTypeEnum.getInfo(vo.getSignType()));
        vo.setCrewAuthStatusStr(AuthStatusEnum.getInfo(vo.getCrewAuthStatus()));
        vo.setAuthStatusStr(AuthStatusEnum.getInfo(vo.getAuthStatus()));

        return vo;
    }

    /**
     * 根据用户id更新用户手机号
     *
     * @param userId 用户id
     * @param mobile 手机号码
     * @author ych
     */
    @Override
    public Boolean updateMobileByUserId(Long userId, String mobile) {
        LambdaQueryWrapper<GcbUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GcbUser::getMobile, mobile);
        Long count = gcbUserMapper.selectCount(wrapper);
        if (count > 0) {
            throw new ValidateException("手机号已被其他账号占用");
        }
        //创建工船宝用户
        GcbUser gcbUser = new GcbUser();
        //设置用户id
        gcbUser.setId(userId);
        //设置用户手机号
        gcbUser.setMobile(mobile);
        return gcbUserMapper.updateById(gcbUser) == 1;
    }

    @Override
    public void updateUserInfo(Long userId, GcbUser user) {
        //转换用户信息
        GcbUser allowGcbUser = allowGcbUserSaveInfo(user);
        allowGcbUser.setId(userId);
        this.save(allowGcbUser);
    }

    /**
     * 获取用户在数据库中的绑定手机号
     *
     * @param userId 用户id
     * @author ych
     */
    @Override
    public String oldMobileNumber(Long userId) {
        //根据用户id查询用户
        GcbUser gcbUser = gcbUserMapper.selectById(userId);
        if (Objects.isNull(gcbUser)) {
            throw new ServiceException("未查询到该用户");
        }
        if (StringUtils.isBlank(gcbUser.getMobile())) {
            throw new ServiceException("用户未绑定手机号");
        }
        return gcbUser.getMobile();
    }

    /**
     * 计算传入时间 与当前时间的时间间隔 返回间隔单位为年
     *
     * @param workDate 传入时间
     * @author ych
     */
    private String calculateWorkTime(Date workDate) {
        // 使用Period类来计算两个日期之间的年数
        if (Objects.isNull(workDate)) {
            return "未知";
        }
        // 将java.util.Date转换为java.time.LocalDate
        LocalDate localStartDate = workDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        // 获取当前日期
        LocalDate currentDate = LocalDate.now();

        return String.valueOf(ChronoUnit.YEARS.between(localStartDate, currentDate));
    }

    /**
     * 转换用户允许保存的字段
     *
     * @param user 用户信息
     * @author ych
     */
    private GcbUser allowGcbUserSaveInfo(GcbUser user) {
        GcbUser updateGcbUser = new GcbUser();
        //头像
        updateGcbUser.setAvatar(user.getAvatar());
        //昵称
        updateGcbUser.setNickName(user.getNickName());
        //性别
        updateGcbUser.setSex(user.getSex());
        //年龄
        updateGcbUser.setAge(user.getAge());
        //城市
        updateGcbUser.setCity(user.getCity());
        //学历
        updateGcbUser.setEducation(user.getEducation());
        //工作时间
        updateGcbUser.setWorkDate(user.getWorkDate());
        //工作经验
        updateGcbUser.setExperience(user.getExperience());
        //标签
        updateGcbUser.setTag(user.getTag());
        return updateGcbUser;
    }

    /**
     * 判断字符串是否全为数字
     *
     * @param input 字符串
     * @author ych
     */
    private boolean isAllDigits(String input) {
        //判断字符串是否为空
        if (input == null || input.isEmpty()) {
            return false;
        }
        //循环判断字符串中是否全部为数字
        for (char c : input.toCharArray()) {
            if (!Character.isDigit(c)) {
                return false;
            }
        }
        return true;
    }

}
